es6块级作用域踩坑
本来以为自己对js作用域这方面已经很了解了,但是看到这样一个简单的问题后,通过查阅却发现这里面其实还有不小的坑。
foo();
if (true) {
function foo() {
console.log('1111');
}
} else {
function foo() {
console.log('2222');
}
}
初看好像没什么难度,由于js函数声明提升,,后面声明的foo覆盖第一个,最后打印2222。
但实际结果却是这样的
经过查阅资料和博客,发现这个问题其实在ES5和ES6中有着天壤之别,并且浏览器的处理方式和语法规定也不相同。
在ES5中是这样规定的
函数只能在顶层作用域和函数作用域之中声明,不能在块级作用域声明
但是es5并没有块级作用域,同时浏览器为了兼容,还是还是支持在块级作用域之中声明函数
如果是这样的话不就是最开始分析的那样了吗,实际上自己在测试的时候使用的是chrome浏览器,chrome是支持es6的,es6对块级作用域内的函数声明处理却是这样的
ES6 引入了块级作用域,明确允许在块级作用域之中声明函数。ES6 规定,块级作用域之中,函数声明语句的行为类似于let,在块级作用域之外不可引用。
按照这种规定,理论上输出的也是1111,但为什么是报错
原来如果改变了块级作用域内声明的函数的处理规则,显然会对老代码产生很大影响。为了减轻因此产生的不兼容问题,ES6在附录B里面规定,浏览器的实现可以不遵守上面的规定,有自己的行为方式。
-允许在块级作用域内声明函数。
-函数声明类似于var,即会提升到全局作用域或函数作用域的头部。
-同时,函数声明还会提升到所在的块级作用域的头部。
所以在浏览器的 ES6 环境中,块级作用域内声明的函数,行为类似于var声明的变量
由于变量提升,实际代码应该是这样的
var foo = undefined
foo();
if (true) {
function foo() {
console.log('1111');
}
} else {
function foo() {
console.log('22222');
}
}
考虑到环境导致的行为差异太大,应该避免在块级作用域内声明函数。如果确实需要,也应该写成函数表达式,而不是函数声明语句。
参考:阮一峰《ECMAScript6入门》